package com.cloud.point.concurrent.general;

import java.util.Random;
import java.util.concurrent.ArrayBlockingQueue;
import java.util.concurrent.BlockingQueue;
import java.util.concurrent.TimeUnit;
import java.util.concurrent.locks.Condition;
import java.util.concurrent.locks.ReentrantLock;

import lombok.extern.slf4j.Slf4j;

/**
 * ReentrantLock使用
 *
 * @author 24373
 * @version 1.0
 * @date 2024-06-15 22:35
 */
@Slf4j
public class TestReentrantLock {

    static final ReentrantLock lock = new ReentrantLock();
    static Condition condition = lock.newCondition();
    static Condition condition2 = lock.newCondition();
    static boolean flag = false;
    static boolean flag2 = false;

    public static void main(String[] args) throws InterruptedException {
        new Thread(() -> {
            lock.lock();
            try {
                long nanos = TimeUnit.SECONDS.toNanos(3);
                while (!flag) {
                    try {
                        log.info("{}等待", Thread.currentThread().getName());
                        /**
                         * 防止重复等待相同时间
                         */
                        if (nanos <= 0) {
                            return;
                        }
                        // 等待并且释放锁
                        nanos = condition.awaitNanos(nanos);
                        log.info("nanos:{},{}", TimeUnit.NANOSECONDS.toSeconds(nanos), Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                log.info("{}完成", Thread.currentThread().getName());
            } finally {
                lock.unlock();
            }
        }, "t1").start();

        new Thread(() -> {
            lock.lock();
            try {
                long nanos = TimeUnit.SECONDS.toNanos(3);
                while (!flag2) {
                    try {
                        log.info("{}等待", Thread.currentThread().getName());
                        /**
                         * 防止重复等待相同时间
                         */
                        if (nanos <= 0) {
                            return;
                        }
                        nanos = condition2.awaitNanos(nanos);
                        log.info("nanos:{},{}", TimeUnit.NANOSECONDS.toSeconds(nanos), Thread.currentThread().getName());
                    } catch (InterruptedException e) {
                        throw new RuntimeException(e);
                    }
                }
                log.info("{}完成", Thread.currentThread().getName());
            } finally {
                lock.unlock();
            }
        }, "t2").start();


        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> {
            log.info("{}开始", Thread.currentThread().getName());
            lock.lock();
            try {
                flag = true;
                condition.signal();
            } finally {
                lock.unlock();
            }
        }, "t1变更线程").start();
        TimeUnit.SECONDS.sleep(1);
        new Thread(() -> {
            log.info("{}开始", Thread.currentThread().getName());
            lock.lock();
            try {
                flag2 = true;
                condition2.signal();
            } finally {
                lock.unlock();
            }
        }, "t2变更线程").start();

    }

    /**
     * 队列实现生产/消费者
     */
    private static void test1() {
        BlockingQueue<String> queue = new ArrayBlockingQueue<>(10);
        Thread producer = new Thread(() -> {
            while (true) {
                try {
                    Random random = new Random();
                    String i = random.nextInt(10) + "";
                    queue.put(i);
                    log.info("put" + i);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });
        Thread consumer = new Thread(() -> {
            while (true) {
                try {
                    String res = queue.poll(100, TimeUnit.MILLISECONDS);
                    log.info("get" + res);
                } catch (InterruptedException e) {
                    throw new RuntimeException(e);
                }
            }
        });

        producer.start();
        consumer.start();
    }

}
